package com.kasax.ipcbus.corel;

import android.content.Context;

import com.kasax.ipcbus.anno.ClassId;
import com.kasax.ipcbus.bean.Request;
import com.kasax.ipcbus.bean.RequestBean;
import com.kasax.ipcbus.bean.RequestParameter;
import com.kasax.ipcbus.bean.Response;
import com.kasax.ipcbus.utils.GsonUtils;
import com.kasax.ipcbus.utils.LogUtils;
import com.kasax.ipcbus.utils.TypeUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 核心框架
 */
public class Hermes {
    // 得到单例
    public static final int TYPE_GET = 1;
    // 得到对象
    public static final int TYPE_NEW = 2;
    private static volatile Hermes sInstance = new Hermes();
    private Context mContext;
    private TypeCenter typeCenter;
    private ServiceConnectManager serviceConnectManager;

    private Hermes() {
        typeCenter = TypeCenter.getInstance();
        serviceConnectManager = ServiceConnectManager.getInstance();
    }


    public static Hermes getDefault() {
        return sInstance;
    }

    public void init(Context context) {
        this.mContext = context.getApplicationContext();

    }

    public void register(Class serviceCls) {
        LogUtils.i(getClass(), "register");
        typeCenter.register(serviceCls);
    }

    /**
     * 连接服务
     *
     * @param context
     * @param serviceClass
     */
    public void connect(Context context, Class<CorelService> serviceClass) {
        connectApp(context, null, serviceClass);
    }

    private void connectApp(Context context, String pkgName, Class<CorelService> serviceClass) {
        LogUtils.i(getClass(), "connectApp");
        init(context);
        serviceConnectManager.bind(context, pkgName, serviceClass);
    }

    /**
     * 获取对象
     *
     * @param clazz
     * @param params
     * @param <T>
     * @return
     */
    public <T> T getInstance(Class<T> clazz, Object... params) {
        Response response = sendRequest(CorelService.class, clazz, null, params);
        T proxy = getProxy(CorelService.class, clazz);
        return proxy;
    }

    private <T> T getProxy(Class<CorelService> corelServiceClass, Class<T> clazz) {
        ClassLoader classLoader = corelServiceClass.getClassLoader();
        T proxy = (T) Proxy.newProxyInstance(classLoader, new Class[]{clazz}, new HermesInvocationHandler(corelServiceClass, clazz));
        // 返回的是类型的代理类
        return proxy;
    }

    private <T> Response sendRequest(Class<CorelService> corelServiceClass, Class<T> clazz, Method method, Object[] params) {
        return execLocalRequest(corelServiceClass, clazz, method, params, TYPE_GET);
    }

    public <T> Response sendObjectRequest(Class<CorelService> corelServiceClass, Class<T> clazz, Method method, Object[] params) {
        return execLocalRequest(corelServiceClass, clazz, method, params, TYPE_NEW);
    }

    private <T> Response execLocalRequest(Class<CorelService> corelServiceClass, Class<T> clazz, Method method, Object[] params, int requestType) {
        RequestBean requestBean = new RequestBean();
        String clazzName = clazz.getName();

        // 设置类名
        if (clazz.getAnnotation(ClassId.class) == null) {
            requestBean.setClsFullName(clazzName);
            requestBean.setResultClsName(clazzName);
        } else {
            clazzName = clazz.getAnnotation(ClassId.class).value();
            requestBean.setClsFullName(clazzName);
            requestBean.setResultClsName(clazzName);
        }

        // 设置方法
        if (method != null) {
            requestBean.setMethodName(TypeUtils.getMethodId(method));
        }

        // 设置参数
        RequestParameter[] requestParameters = null;
        if (params != null && params.length > 0) {
            requestParameters = new RequestParameter[params.length];
            for (int i = 0; i < params.length; i++) {
                Object p = params[i];
                String clsName = p.getClass().getName();
                String jsonData = GsonUtils.toJson(p);
                RequestParameter parameter = new RequestParameter(clsName, jsonData);
                requestParameters[i] = parameter;
            }
        }
        if (requestParameters != null) {
            requestBean.setRequestParameters(requestParameters);
        }

        String requestBeanJson = GsonUtils.toJson(requestBean);
        LogUtils.i(getClass(), "execLocalRequest requestBeanJson: " + requestBeanJson);
        Request request = new Request(requestBeanJson, requestType);
        return serviceConnectManager.request(corelServiceClass, request);
    }
}
